/* Copyright (C) 2015 Daniyaal Rasheed <radonapps@gmail.com>

   This file is part of the Dekko email client for Ubuntu Touch/

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "ImapLogModel.h"
#include "Common/InvokeMethod.h"

namespace Dekko
{

LogItem::LogItem(QObject *parent) : QObject(parent)
{
}

QString LogItem::text() const
{
    return m_text;
}

void LogItem::setText(const QString &text)
{
    m_text = text;
}

QDateTime LogItem::time() const
{
    return m_time;
}

void LogItem::setTime(const QDateTime &time)
{
    m_time = time;
}

ImapLog::ImapLog(QObject *parent) : QObject(parent),
    m_log(0)
{
    m_log = new QQmlObjectListModel<LogItem>(this);
}

QObject *ImapLog::account() const
{
    return m_account;
}

QObject *ImapLog::log() const
{
    return m_log;
}

QString ImapLog::description() const
{
    return static_cast<Settings::AccountProfile *>(m_account->profile())->description();
}

void ImapLog::setAccount(QObject *account)
{
    Accounts::Account *a = static_cast<Accounts::Account *>(account);
    Q_ASSERT(a);
    if (m_account.data() == a) {
        return;
    }
    if (!m_account.isNull()) {
        disconnect(m_account->imapModel(), 0, this, 0);
    }
    m_account = a;
    if (!m_log->isEmpty()) {
        m_log->clear();
    }
    Imap::Mailbox::Model *model = static_cast<Imap::Mailbox::Model *>(m_account->imapModel());
    Q_ASSERT(model);
    connect(model, &Imap::Mailbox::Model::logged, this, &ImapLog::handleSomethingLogged);
    emit accountChanged();
}

void ImapLog::handleSomethingLogged(uint parserId, const Common::LogMessage &message)
{
    Q_UNUSED(parserId);
    if (message.message.isEmpty()) {
        return;
    }

    QString text;
    // The part of the log we are interested in is always at the start
    // so truncate at 200
    enum {TRUNCATE_POINT=200};
    if (message.message.size() > TRUNCATE_POINT) {
        text = message.message.left(TRUNCATE_POINT);
    } else {
        text = message.message;
    }

    Type type = INVALID;
    switch (message.kind) {
    case Common::LOG_IO_WRITTEN:
        type = IO_WRITE;
        break;
    case Common::LOG_IO_READ:
        type = IO_READ;
        break;
    case Common::LOG_MAILBOX_SYNC:
    case Common::LOG_MESSAGES:
    case Common::LOG_OTHER:
    case Common::LOG_PARSE_ERROR:
    case Common::LOG_TASKS:
        type = OTHER;
        break;
    }
    if (m_log->count() > LOG_LIMIT) {
        m_log->remove(m_log->first());
    }
    // No need to set a parent here as QQmlObjectListModel will reparent it and manage it's
    // memory allocations.
    LogItem *item = new LogItem(0);
    item->setText(formatMessage(message.timestamp, text, type));
    item->setTime(message.timestamp);
    CALL_LATER(m_log, append, Q_ARG(QObject*, item));
}

QString ImapLog::formatMessage(const QDateTime &timeStamp, const QString &message, const ImapLog::Type &type)
{
    if (message.isEmpty()) {
        return QString();
    }
    QString ts = timeStamp.toString("hh:mm:ss.zzz");
    QString text;
    // By default it just returns the message unchanged
    switch (type) {
    case IO_READ:
        text = QStringLiteral("<font color=\"#f09609\">[%1]&nbsp;</font><font color=\"#ee4035\">&lt;&lt;&lt;&nbsp;</font><font color=\"#f37736\"><b>%2</b></font>").arg(ts, message);
        break;
    case IO_WRITE:
        text = QStringLiteral("<font color=\"#f09609\">[%1]&nbsp;</font><font color=\"#7bc043\">&gt;&gt;&gt;&nbsp;</font><font color=\"#00aba9\">%2").arg(ts, message);
        break;
    case OTHER:
    case INVALID:
        text = QStringLiteral("<font color=\"#f09609\">[%1]&nbsp;</font><font color=\"#9AD3EB\">%2</font>").arg(ts, message);
    }
    if (text.isEmpty()) {
        text = message;
    }
    return text;
}

}
